Repository navigation
fix(oauth): send a bare Bearer challenge when a request has no credentials - #230
Open
Jordan Harband (ljharb) wants to merge 2 commits into
Open
Jordan Harband (ljharb) wants to merge 2 commits into
Jordan Harband (ljharb) wants to merge 2 commits into
Conversation
Jordan Harband (ljharb)
requested review from
Joseph Werle (jwerle) and
Vasco Santos (vasco-santos)
November 4, 2026 17:46
Joseph Werle (jwerle)
approved these changes
Nov 4, 2026
3 tasks
Contributor
Author
|
(before I land this, I'm going to put up another PR removing the failing GHCR stuff) |
…tials An OAuth-enabled server already challenges every MCP request, initialize and tools/list included. A request with no Authorization header, or with a scheme other than Bearer, now gets the RFC 6750 §3.1 form the MCP authorization spec shows: WWW-Authenticate: Bearer resource_metadata="…", scope="…" with no error code, instead of error="invalid_request". The scope list is the resource's own scopes (offline_access dropped), so clients do not fall back to the issuer's full scopes_supported. The JSON body still names the problem. A "Bearer" header with no token, and every token-validation failure, keep their error codes. Non-OAuth HTTP and stdio are unchanged. Tests pin the exact challenge on anonymous initialize and tools/list across replicas, with the hosted scope set, plus the no-scope and offline_access cases. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Collaborator
|
Landed some fixes, Jordan Harband (@ljharb) try again with an updated branch. |
Jordan Harband (ljharb)
force-pushed
the
fix/oauth-bare-challenge-on-connect
branch
from
November 5, 2026 21:43
355c5e5 to
3914ac6
Compare
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When OAuth is enabled, a request with no
Authorizationheader, or with a scheme other than Bearer, now gets the RFC 6750 §3.1 challenge with no error code. This is the form the MCP authorization spec shows:Before, it also carried
error="invalid_request", error_description="…". Unchanged:Bearerheader with no token, and every token-validation failure, keep their error codes.scope=isSOCKET_OAUTH_REQUIRED_SCOPESminusoffline_access, the same list as PRMscopes_supported. Clients therefore ask for the resource's read scopes, not the authorization server's full list.Why: Cursor hosted OAuth
Cursor only enters its needsAuth / Authenticate state when it gets a 401 during the connect phase (forum thread).
On
main,routeRequestalready authenticates every MCP request,initializeandtools/listincluded. But a probe of production on 2026-11-04 shows behavior that isn't in this repo:https://mcp.socket.dev/initializetools/callerror="invalid_request", error_description="Authentication required for this tool", resource_metadata="…"(noscope=)initializewith a bogus Bearerinvalid_token …, scope="packages:list alerts:list threat-feed:list"(matchesmain)The string
Authentication required for this tooldoesn't appear in this repo or its history. The hosted deployment needs a change too. Merging this alone won't move the Cursor row in the README compatibility matrix. Once anonymousinitializeon production returns 401, re-test that row, and the Claude Code, Codex and Zed rows (their pre-login flow changes).Tests
http-replicas.test.mts): exact challenge on anonymousinitializeandtools/listthrough real replicas, with the hosted scope set and a matchingscopes_supported.invalid_requestkept forBearer/bearerwith no token; lowercasebearer <token>still reaches introspection (mutation-checked);offline_accessdropped fromscope=;scope=omitted when no scopes are configured;writeOAuthChallengeheader and body.I ran the tests locally without the fleet pack, which couldn't be fetched, using a minimal vitest config. 525/525 pass. The suites that import
scripts/fleet/**didn't load. CI is the real gate for lint and those suites.🤖 Generated with Claude Code
Note
Medium Risk
Changes OAuth 401 response shape on the MCP auth path, which can affect client sign-in behavior, but scope is limited to pre-credential cases and aligns with RFC/MCP expectations.
Overview
OAuth-enabled MCP requests with no
Authorizationheader or a non-Bearer scheme now get a bareWWW-Authenticatechallenge (Bearer resource_metadata=…, scope=…) withouterror=/error_description=in the header, per RFC 6750 §3.1 and the MCP connect-handshake signal clients like Cursor expect oninitialize/tools/list.Adds
buildBearerChallengeandwriteOAuthChallengeinhttp.mts, refactorswriteOAuthErrorto share header assembly, and routes missing / wrong-scheme cases inauthenticateRequestthrough the new helper. Malformed Bearer (scheme present but no token) and post-introspection failures still use codedwriteOAuthErrorchallenges; the JSON body still describes the problem.Tests assert the exact challenge on anonymous
initializeandtools/list, Bearer case handling,offline_accessomitted fromscope=, and unit coverage for the new writers.Reviewed by Cursor Bugbot for commit 211cf16. Configure here.